#    Copyright 2011 Tri-County Electric Cooperative, St. Matthews, South Carolina
#    This file is part of COOPIP.
#    COOPIP is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#    COOPIP is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with COOPIP.  If not, see <http://www.gnu.org/licenses/>.

#************************BEGIN Add Include Files to Path************************
import sys

IncludePath="/var/coopip/djangoproject/include"
if(not IncludePath in sys.path):
    sys.path.append(IncludePath)


    
#************************END   Add Include Files to Path************************
from django.contrib.gis.geos import *
import os, time, psycopg2, datetime

#********************Setup psycopg2 and django section********************
PathDjangoRoot="/opt/coopip/"
if(not PathDjangoRoot in sys.path):
    sys.path.append(PathDjangoRoot)
from django.core.management import setup_environ
import djangoproject.settings
setup_environ(djangoproject.settings)
from djangoproject.models import *
from django.contrib.gis.geos import GEOSGeometry
import CIS, AMR, OMS, GIS
import COOPIP_Misc
#********************Setup psycopg2 and django section********************


import urllib
import httplib
import datetime
        
SubstationsChecked = {}



def BasicSetMetersToPingByPercent(PercentToPing = 0.001):
    Substations=amrcache.Substation.objects.all()
    MetersToPing=[]
    for substation in Substations:
        if(not COOPIP_Misc.MakeSureNotTooManyPendingMeterPings(substation)):
            continue  #Do not send pings out if there are too may pending in COOPIP [waiting to be sent to AMR because substations are offline or too many are in AMR]
        if(substation.Name == 'UNKNOWN'):
            continue
        MetersOnSubstationCount=djangoproject.models.ipbase.Meter.objects.exclude(IncidentSymbology='deleted').filter(Substation=substation).count()
        NumberToPing=int(PercentToPing * MetersOnSubstationCount)
        if(not NumberToPing and MetersOnSubstationCount):
            NumberToPing = 1
        if(djangoproject.models.ipbase.Meter.objects.filter(Substation=substation).filter(SendPingToAMRIndicator=True).count()):
            continue
        print substation.Name + str('    pinging:   ') + str(NumberToPing) + '   of   '  + str(MetersOnSubstationCount)
        MetersOnSubstation=Meter.objects.filter(Substation=substation).order_by('LastPingOutDateTime')
        Count = 0
        while(Count < NumberToPing):
            meter = MetersOnSubstation[Count]
            meter.SendPingToAMRIndicator=True
            meter.save()
            Count = Count + 1
    Now=datetime.datetime.now()

    

    FailedMeters=list(djangoproject.models.ipbase.Meter.objects.filter(IncidentSymbology__in=['failed_with_open_incident', 'open_incident', 'failed', 'amrfailure', 'substationfailure']).order_by('LastPingOutDateTime'))  #Attempt to ping the oldest 5 failed meters, even on slow pinging
    print "Failed Meters:  " + str(len(FailedMeters))
    CountPerSubstation = {}
    for meter in FailedMeters:
        if(not CountPerSubstation.has_key(meter.Substation.Name)):
            CountPerSubstation[meter.Substation.Name] = 0
        if(CountPerSubstation[meter.Substation.Name] > 3):
            continue
        SecondsSinceLastPingAttempt = (Now - meter.LastPingOutDateTime).total_seconds()
        if(SecondsSinceLastPingAttempt > 900):  
            meter.SendPingToAMRIndicator=True
            meter.save()
            print "Pinging failed meter:  " + str(meter.SerialNumber) + '  Last Ping Attempt:  ' +  str(meter.LastPingOutDateTime)
            CountPerSubstation[meter.Substation.Name] = CountPerSubstation[meter.Substation.Name] + 1
        else:
            print "Skipping failed meter:  " + str(meter.SerialNumber) + "  Last Ping attempt was:  " + str(SecondsSinceLastPingAttempt) + " seconds ago."
    
    
        

def SetPingTopMeters(PotentialMeters, PingRate):
    CurrentTime=datetime.datetime.now()
    CurrentHour=CurrentTime.hour
    TimeDelay = 60 * 5 #seconds

    if(not PingRate in ['normal', 'high']):
        return
    if(CurrentHour in djangoproject.settings.MeterPingSlowHours):
        return

    if(PingRate == 'high' and CurrentHour in djangoproject.settings.MeterPingFastHours):
        NumberOfMetersToPing = 5
    elif(PingRate == 'high'):
        NumberOfMetersToPing = 2
    
    if(PingRate == 'normal' and CurrentHour in djangoproject.settings.MeterPingFastHours):
        NumberOfMetersToPing = 2
    elif(PingRate == 'normal'):
        NumberOfMetersToPing = 1


    Count = 0

    for meter in PotentialMeters:
        if(not SubstationsChecked.has_key(meter.Substation.id)):
            SubstationsChecked[meter.Substation.id] = MakeSureNotTooManyPendingMeterPings(meter.Substation)
        if(not SubstationsChecked[meter.Substation.id]):
            continue  #Do not send pings out if there are too may pending in COOPIP [waiting to be sent to AMR because substations are offline or too many are in AMR]
 
        if(Count < NumberOfMetersToPing):
            if(meter.LastPingOutDateTime and ((CurrentTime - meter.LastPingOutDateTime).total_seconds() < (TimeDelay))):
                break  #Do not ping meters more often than the specified time interval, meters are sorted in order of last ping out date
            meter.SendPingToAMRIndicator=True
            meter.save()
            Count = Count + 1
        else:
            break
        
        
def AdvancedSetMetersToPingByCircuit():
    Circuits=list(djangoproject.models.ipbase.Meter.objects.all().exclude(IncidentSymbology='deleted').values_list('GISCircuitNumber', flat=True).distinct())
    PingRate = COOPIPSetting.GetPingRate()

    CurrentTime=datetime.datetime.now()
    CurrentHour=CurrentTime.hour
    Circuits.sort()
    if(PingRate == 'off'):
        return
    if(PingRate == 'low' or CurrentHour in djangoproject.settings.MeterPingSlowHours):  
        BasicSetMetersToPingByPercent()
        return
    #for meters with open incidents that haven't been pinged within 30 min; reping even if successful; ping oldest 5 on outage list 

    for circuit in Circuits:
        SuccessfulMetersOnCircuit=djangoproject.models.ipbase.Meter.objects.filter(GISCircuitNumber=circuit).filter(IncidentSymbology__in=['success', 'investigation', 'activebutnotauthorized', 'notactive', 'serviceorder']).order_by('LastPingOutDateTime')
        FailedMetersOnCircuit=djangoproject.models.ipbase.Meter.objects.filter(GISCircuitNumber=circuit).filter(IncidentSymbology__in=['failed_with_open_incident', 'open_incident', 'substationfailure', 'amrfailure', 'failed']).order_by('LastPingOutDateTime')
        NeverAttemptedPingMeters=djangoproject.models.ipbase.Meter.objects.filter(GISCircuitNumber=circuit).exclude(IncidentSymbology='deleted')
        SetPingTopMeters(SuccessfulMetersOnCircuit, PingRate)
        SetPingTopMeters(FailedMetersOnCircuit, PingRate)
        SetPingTopMeters(NeverAttemptedPingMeters, PingRate)


Start = datetime.datetime.now()
SecondsElasped = (Start - datetime.datetime.now()).total_seconds()
AdvancedSetMetersToPingByCircuit()
while(SecondsElasped < 60):
    MeterPing().PingWaitingMeters()
    time.sleep(15)
    SecondsElasped = (datetime.datetime.now() - Start).total_seconds()


